using System;
using System.Net.Sockets;
using BitTorrent.Agents;
using BitTorrent.Ccr.Adapters.IO;
using BitTorrent.Client.Peer.Message;
using Microsoft.Ccr.Core;
using BitTorrent.Agents.Messages;

namespace BitTorrent.Client.Peer
{
    internal class PeerConnection : AgentBase {
        private SocketAgent _socketPort;

        public PeerConnection(IPeer peer, DispatcherQueue dispatcherQueue) : base(dispatcherQueue) {
            Port = new Port<PeerMessage>();

            // TODO: Have to handle the exception that the SocketAdapter can send as a message.
            var socket = new Socket(peer.PeerEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
            var connect = SocketAdapter.Connect(socket, peer.PeerEndPoint, TaskQueue);
            Activate(Arbiter.Receive(false, connect.P0, ConnectionHandler));

            Activate(Arbiter.Interleave(
                         new TeardownReceiverGroup(),
                         new ExclusiveReceiverGroup(),
                         new ConcurrentReceiverGroup(Arbiter.Receive(true, Port, SendPeerMessageHandler))));
        }

        private void ConnectionHandler(Socket socket) {
            // Send handshake message
        }

        public Port<PeerMessage> Port { get; set; }

        private void SendPeerMessageHandler(PeerMessage message) {
            byte[] payload = message.GetMessage();
            _socketPort.Port.Post(new WritePacket(payload));
        }
    }

    internal class PeerAgent : AgentBase
    {
        private SocketAgent _socketPort;

        public PeerAgent(IPeer peer, DispatcherQueue dispatcherQueue)
            : base(dispatcherQueue) {
            Port = new Port<SendPeerMessage>();

            var socket = new Socket(peer.PeerEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
            socket.Connect(peer.PeerEndPoint);
             _socketPort= new SocketAgent(socket, TaskQueue);

            Activate(Arbiter.Interleave(
                new TeardownReceiverGroup(),
                new ExclusiveReceiverGroup(),
                new ConcurrentReceiverGroup(Arbiter.Receive(true, Port, SendPeerMessageHandler))));
        }

        public Port<SendPeerMessage> Port { get; set; }

        private void SendPeerMessageHandler(SendPeerMessage message) {
            byte[] payload = message.Message.GetMessage();
            _socketPort.Port.Post(new WritePacket(payload));
        }
    }
}
